package ar.edu.caece.compiler.grammar.factories;

import ar.edu.caece.compiler.grammar.AbstractTokenVisitorFactory;
import ar.edu.caece.compiler.grammar.Recognizer;
import ar.edu.caece.compiler.grammar.TokenRecognizer;
import ar.edu.caece.compiler.grammar.TokenVisitor;
import ar.edu.caece.compiler.grammar.attributes.Attribute;
import ar.edu.caece.compiler.grammar.attributes.ListaParametrosAttribute;
import ar.edu.caece.compiler.grammar.attributes.StringAttribute;
import ar.edu.caece.compiler.grammar.attributes.Attribute.Type;
import ar.edu.caece.compiler.grammar.attributes.tree.NodeParametrosFuncion;
import ar.edu.caece.compiler.grammar.attributes.tree.NodeValor;
import ar.edu.caece.compiler.grammar.nonterminals.OTROSA;
import ar.edu.caece.compiler.grammar.nonterminals.PASOPAM2;
import ar.edu.caece.compiler.grammar.nonterminals.VALOR;


public class PASOPAM2Factory extends AbstractTokenVisitorFactory {

	private static PASOPAM2Factory INSTANCE;
	
	public static PASOPAM2Factory getInstance() throws Exception {
		if(INSTANCE==null) INSTANCE = new PASOPAM2Factory();
		return INSTANCE;
	}
	
	private VALORFactory valorFactory;
	private OTROSAFactory otrosaFactory;
	private TokenVisitor parseVALOR;
	private TokenVisitor parseOTROSA;
	
	private Initializer initializer = new Initializer() {
		
		@Override
		public void init() throws Exception {
			initializer = NoOperationInitializer.getInstance();
			valorFactory = VALORFactory.getInstance();
			otrosaFactory = OTROSAFactory.getInstance();
			parseOTROSA = otrosaFactory.makeVisitor();
			parseVALOR = valorFactory.makeVisitor();
		}
	};
	
	private PASOPAM2Factory() throws Exception {

	}
	
	@Override
	public TokenVisitor makeChainedVisitor(
			final TokenVisitor siguiente) throws Exception {
		initializer.init();

		return new TokenVisitor() {

			@Override
			public Recognizer defaultCase(TokenRecognizer llamador)
					throws Exception {
				TokenVisitor parser = valorFactory.makeChainedVisitor(siguiente);
				parser.setInheretedAttributes(getAttributes());
				Recognizer result = llamador.execute(parser);
				if(result instanceof VALOR) {
					NodeParametrosFuncion nodeLlamada = (NodeParametrosFuncion) getAttribute(Attribute.ARBOL_HEREDADO);

					ListaParametrosAttribute listaParametros = (ListaParametrosAttribute) getAttribute(Attribute.LISTA_PARAMETROS_HEREDADA);
					
					VALOR valor = (VALOR) result;
					
					listaParametros.addParametro(new StringAttribute(valor.getAttribute("tipo").toString()));
					
					parseOTROSA.addInheritedAttribute(Attribute.LISTA_PARAMETROS_HEREDADA, listaParametros);
					parseOTROSA.addInheritedAttribute(Attribute.LISTA_PARAMETROS_SINTETIZADA, getAttribute(Attribute.LISTA_PARAMETROS_SINTETIZADA));
					
					NodeValor nodoValor = new NodeValor();
					nodoValor.setTipo(Type.valueOf(valor.getAttribute("tipo").toString()));
					nodoValor.setValor(valor.getAttribute("valor").toString());
					nodeLlamada.addParametro(nodoValor);

					parseOTROSA.addInheritedAttribute(Attribute.ARBOL_HEREDADO, nodeLlamada);
					
					OTROSA otrosa = (OTROSA) nextToken().execute(parseOTROSA);
					PASOPAM2 pasopam2 = new PASOPAM2 (valor, otrosa);
					
					pasopam2.addAttribute(Attribute.ARBOL_SINTETIZADO, otrosa.getAttribute(Attribute.ARBOL_SINTETIZADO));
					return pasopam2;				} 
				else {
					return result;
				}
			}
			
		};
	
	}
	@Override
	public TokenVisitor makeVisitor() throws Exception {
		initializer.init();

		return new TokenVisitor() {

			@Override
			public Recognizer defaultCase(TokenRecognizer llamador) throws Exception {
				NodeParametrosFuncion nodeLlamada = (NodeParametrosFuncion) getAttribute(Attribute.ARBOL_HEREDADO);

				ListaParametrosAttribute listaParametros = (ListaParametrosAttribute) getAttribute(Attribute.LISTA_PARAMETROS_HEREDADA);
				
				VALOR valor = (VALOR) llamador.execute(parseVALOR);
				
				listaParametros.addParametro(new StringAttribute(valor.getAttribute("tipo").toString()));
				
				parseOTROSA.addInheritedAttribute(Attribute.LISTA_PARAMETROS_HEREDADA, listaParametros);
				parseOTROSA.addInheritedAttribute(Attribute.LISTA_PARAMETROS_SINTETIZADA, getAttribute(Attribute.LISTA_PARAMETROS_SINTETIZADA));
				
				NodeValor nodoValor = new NodeValor();
				nodoValor.setTipo(Type.valueOf(valor.getAttribute("tipo").toString()));				nodoValor.setValor(valor.getAttribute("valor").toString());
				nodeLlamada.addParametro(nodoValor);

				parseOTROSA.addInheritedAttribute(Attribute.ARBOL_HEREDADO, nodeLlamada);
				
				OTROSA otrosa = (OTROSA) nextToken().execute(parseOTROSA);
				PASOPAM2 pasopam2 = new PASOPAM2 (valor, otrosa);
				
				pasopam2.addAttribute(Attribute.ARBOL_SINTETIZADO, otrosa.getAttribute(Attribute.ARBOL_SINTETIZADO));

				
				return pasopam2;
			}
		};
	}
	
	
}
